'use strict';

const bcrypt = require('bcryptjs');
const { Service } = require('egg');
const { Op } = require('sequelize');
const wxconfig = require("../../config/wx");
const wxH5config = require("../../config/wxH5");
const WXBizDataCrypt = require('../../config/WXBizDataCrypt');
class UserService extends Service {
    /**
     * 根据分页和搜索条件获取用户信息
     * @param {Object} where 查询用户的条件
     * @param {Number} page 当前分页
     * @param {Number} pageSize 当前页每页多少条
     */
    async getUserRolePermissions(where, page, pageSize) {
        const { Member } = this.ctx.model;
        return Member.findAndCountAll({
            attributes: { exclude: ['password'] },
            where: {
                ...where,
            },
            order:[
                // id 降序
                ['create_time','DESC']
            ],
            offset: pageSize * (page - 1),
            limit: pageSize,
        });
    }
    /**
     * 注册用户数据
     * @param {Object} data
     */
    async registerUser(data) {
        const { Member } = this.ctx.model;
        if (!data.username) {
            throw new Error('请输入账号');
        }
        const userExists = await Member.findOne({
            attributes: ['id'],
            where: {
                username: data.username,
            },
        });
        if (userExists) throw new Error('该账号已经存在');
        const newUser = await Member.create(data);
        return newUser.dataValues;
    }

    /**
     * 根据条件查询用户信息
     * @param {Object} user
     */
    async loginByEmail({ username, password }) {
        const { Member } = this.ctx.model;
        // 根据邮箱查询用户是否存在
        let user = await Member.findOne({
            where: { username },
        });
        if (!user) throw new Error('账号不存在');
        // 判断密码是否有误
        const isValid = user.password === password
        if (!isValid) {
            throw new Error('密码错误');
        }
        user = user.dataValues;
        delete user.password;
        return user;
    }
    async login(data) {
        let { phone, nickname, password, code } = data;
        const { Member } = this.ctx.model;
        // 校验open_id
        // 调用微信api https://api.weixin.qq.com/sns/jscode2session，获取openid
        const wxRes = await this.ctx.curl(`https://api.weixin.qq.com/sns/jscode2session?appid=${wxconfig.appid}&secret=${wxconfig.secret}&js_code=${code}&grant_type=authorization_code`, {dataType: 'json'})
        console.log('wxRes',wxRes)
        if (wxRes.data.errcode) {
            throw new Error(wxRes.data.errmsg);
        }
        const openid = wxRes.data.openid;
        console.log('openid',openid)
        // 根据手机号查询用户是否存在
        let user = await Member.findOne({
            where: {
                openid,
            },
        });
        if (!user) {
            // 去注册
            let user2 = await Member.create({
                phone,
                password,
                openid,
                nickname: nickname ? nickname : '用户' + phone.slice(-4),
            })
            let userValue = user2.dataValues;
            delete userValue.password;
            return userValue;
        } else {
            // 判断密码是否有误
            const isValid = user.password === password
            if (!isValid) {
                throw new Error('密码错误');
            }
            return user.dataValues
        }
    }

    async wxlogin(data) {
        const { code, encryptedData, iv } = data;
        try {
            const { session_key, openid} = await this.exchangeCodeForSessionKey(code)
            const phoneNumber = await this.decryptPhoneNumber(session_key, encryptedData, iv)
            console.log('phoneNumber',phoneNumber)
            return await this.loginForm(openid, phoneNumber)
        } catch (error) {
            console.log('error',error)
            throw new Error('登录失败');
        }
    }
    async wxH5login(data) {
        const { code } = data;
        try {
            const { access_token, openid} = await this.getWxH5OpenId(code)
            const userInfo = await this.getWxH5UserInfo(access_token, openid)
            return await this.loginFormWxH5(userInfo)
        } catch (error) {
            console.log('error',error)
            throw new Error('登录失败');
        }
    }
    async getWxH5OpenId(code) {
        const url = `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${wxH5config.appid}&secret=${wxH5config.secret}&code=${code}&grant_type=authorization_code`;
        const response = await this.ctx.curl(url, { dataType: 'json' });
        console.log(response)
        if (response.status === 200) {
            if (response.data.errcode) {
                throw new Error(response.data.errmsg);
            } else {
                /**
                 *  access_token: '83_vhk2_5FyIg97ShefJqezlqQCD4AWeK7xToK2FzN-hbafuRBe_n6I3sTJvYLqfXtzwxowrdC6pAvPoovRpE6FWo1N2iRqeHkFocWX8E7PUwE',
                 *     expires_in: 7200,
                 *     refresh_token: '83_J7zVVBAdPr57dswqn4Dz4Z9QPPw_IGKEyIICuEkLgsc21TtnmBGTQhos8iheGoZePmIvuQfobJhbnmvZbjdp64m9-hHQODIGZRIeQUGYF5I',
                 *     openid: 'oG5mi6YItlS1bcV96H96nM6B0QIs',
                 *     scope: 'snsapi_userinfo'
                 */
                return {
                    openid: response.data.openid,
                    access_token: response.data.access_token,
                }
            }
        } else {
            throw new Error('登录失败');
        }
    }
    async getWxH5UserInfo(access_token, openid) {
        const url = `https://api.weixin.qq.com/sns/userinfo?access_token=${access_token}&openid=${openid}&lang=zh_CN`;
        const response = await this.ctx.curl(url, { dataType: 'json' });
        console.log(response)
        if (response.status === 200) {
            if (response.data.errcode) {
                throw new Error(response.data.errmsg);
            } else {
                return response.data
            }
        } else {
            throw new Error('登录失败');
        }
    }
    async loginFormWxH5(userInfo) {
        console.log(userInfo)
        const {
            openid,
            nickname,
            sex,
            headimgurl,
            unionid
        } = userInfo;
        const { Member } = this.ctx.model;
        // 根据手机号查询用户是否存在
        let user = await Member.findOne({
            where: {
                h5_openid: openid,
            },
        });
        if (!user) {
            // 去注册
            let createUser = await Member.create({
                password: '123456',
                h5_openid: openid,
                source: 'wx_h5',
                unionid,
                sex,
                nickname: nickname,
                avatar_url: headimgurl,
            })
            let userValue = createUser.dataValues;
            delete userValue.password;
            console.log('userValue',userValue)
            return userValue;
        } else {
            // // 判断密码是否有误
            // const isValid = user.password === password
            // if (!isValid) {
            //     throw new Error('密码错误');
            // }
            return user.dataValues
        }
    }
    async loginForm(openid, phone) {
        const { Member } = this.ctx.model;
        // 根据手机号查询用户是否存在
        let user = await Member.findOne({
            where: {
                openid
            },
        });
        console.log('findUser',user)
        if (!user) {
            // 去注册
            let createUser = await Member.create({
                phone,
                password: '123456',
                openid,
                nickname: '用户' + phone.slice(-4),
            })
            console.log('createUser',createUser)
            let userValue = createUser.dataValues;
            delete userValue.password;
            console.log('userValue',userValue)
            return userValue;
        } else {
            // // 判断密码是否有误
            // const isValid = user.password === password
            // if (!isValid) {
            //     throw new Error('密码错误');
            // }
            return user.dataValues
        }
    }
    async exchangeCodeForSessionKey(code) {
        const url = `https://api.weixin.qq.com/sns/jscode2session?appid=${wxconfig.appid}&secret=${wxconfig.secret}&js_code=${code}&grant_type=authorization_code`;
        const response = await this.ctx.curl(url, { dataType: 'json' });
        const data = response.data;
        console.log(data)
        if (!data.session_key || !data.openid) {
            throw new Error('Failed to exchange code for session_key and openid');
        }

        return {
            session_key: data.session_key,
            openid: data.openid,
        };
    }
    async decryptPhoneNumber(session_key, encryptedData, iv) {
        const pc = new WXBizDataCrypt(wxconfig.appid, session_key);
        const data = {};

        const errCode = pc.decryptData(encryptedData, iv, data);
        return errCode.phoneNumber
    }
    async findOne(id) {
        const findRes = await this.ctx.model.Member.findOne({
            where: {
                id,
            },
        });
        if (!findRes) {
            throw new Error('用户不存在');
        }
        return findRes;
    }

    /**
     * 根据id删除对应的用户
     * @param {Number} uid
     */
    async deleteUserById(id) {
        // 删除前先删除地址
        await this.ctx.model.Address.destroy({ where: { member_id: id } });
        return await this.updateUserById(id, { is_del: 1 });

    }

    /**
     * 根据ID修改用户信息
     * @param {Number} id 用户ID
     * @param {Object} data 要修改的用户信息
     */
    async updateUserById(id, data) {
        const { Member } = this.ctx.model;
        const { username } = data;
        const andWhere = { id: { [Op.ne]: id } };
        let neenCheck = false;
        if (username) {
            neenCheck = true;
            andWhere.username = username;
        }

        if (neenCheck) {
            const userExists = await Member.findOne({
                attributes: ['id'],
                where: { [Op.and]: andWhere },
            });
            if (userExists) throw new Error('该账号已注册');
        }

        return await Member.update(data, { where: { id } });
    }
    /**
     * 更新用户密码
     * @param {Number} id 用户ID
     * @param {Object} data 新密码和旧密码
     */
    async updatePassword(id, data) {
        const { Member } = this.ctx.model;
        const user = await Member.findByPk(id);
        if (!user) {
            throw new Error('该账号不存在');
        }

        // 旧密码是否有误, 正确就直接修改
        const isValid = bcrypt.compareSync(data.old_password, user.password);
        if (!isValid) {
            throw new Error('旧密码输入不正确');
        }
        user.password = data.new_password;
        return await user.save();
    }

    // 所有列表
    async allList(where) {
        const { Member } = this.ctx.model;
        return Member.findAll({
            where,
            order:[
                // id 降序
                ['create_time','DESC']
            ],
        });
    }
}

module.exports = UserService;
